package chess;
import game.ChessGame;

import java.util.ArrayList;

public class ChessClock{
	
	public final static int MAX_NUM_MINUTES = 10;//10 minutes
	public static final long ONE_MINUTE = 60000;
	public final static long MAXTIME = ONE_MINUTE * MAX_NUM_MINUTES; //10 min in milliseconds
	public final static int MAX_TIME_STRING_LENGTH= 5 ; //Max number of characters before a string is weird
	
	private ArrayList<Long> playerW_elapsed; //time is in millisecond so for long times of the cpu clock number maybe large
	private ArrayList<Long> playerB_elapsed;
	private boolean clock_enable;
	private long starttime;
	private long endtime;
	private Player currentPlayer;
	
	/**
	 * Chess clock is a 10 minute countdown timer.  Each player gets a total of ten minutes
	 * to make their moves.
	 * @param game The game being played
	 */
	public ChessClock(ChessGame game) {
		this.clock_enable=true;
		//Uses arraylist to dynamically track time and allow for undos up to beginning
		this.playerW_elapsed= new ArrayList<Long>();
		this.playerB_elapsed= new ArrayList<Long>();
		 
		long zero=0; //used to avoid type confusion in initial value
		this.playerW_elapsed.add(zero);
		this.playerB_elapsed.add(zero);
		
		//this should always be the white player, based on normal chess rules
		this.currentPlayer=game.getCurrentPlayer();
			
	}
	
	/**
	 * Resets the clocks back to no time elapsed.
	 * 
	 * Ie. this gives the players all of their time back.
	 */
	public void resetClock(){
		this.playerB_elapsed.clear();
		this.playerW_elapsed.clear();
		
		long zero=0; //used to avoid type confusion in initial value
		this.playerW_elapsed.add(zero);
		this.playerB_elapsed.add(zero);
		this.currentPlayer=((ChessGame)currentPlayer.getGame()).getCurrentPlayer();
	}
	
	/**
	 * Sets the start of a player turn
	 */
	private void getRoundstart(){
		// Get current time
		starttime = System.currentTimeMillis();
	}
	
	/**
	 * Sets the end of a player turn
	 */
	private void getRoundend(){
		// Get current time
		endtime = System.currentTimeMillis();
	}
	
	/**
	 * Find the amount of time that the player took on their turn
	 * @return The amount of time taken on the turn
	 */
	private long findElapsed(){
		//simple math
		return endtime - starttime;
	}
	
	/**
	 * This enables the clock.  Note that it doesn't actually turn it off,
	 * rather, it just allows it to be hidden
	 * 
	 * @param status Whether or not you want it hidden
	 */
	public void enabled (boolean status){
		//toggle for the clock, with be used to hide frame
		this.clock_enable=status;
	}
	
	/**
	 * Gets the player whose turn the clock thinks it is
	 * @return The current player according to the clock
	 */
	public Player getCurPlayer(){
		return this.currentPlayer;
	}
	
	
	/**
	 * Adds an amount of time to the players time banks
	 * @param player The player who took some time
	 * @param time The amount of time to add to the players time banks
	 */
	public void updateTime(Player player, long time){
		if (player.getColour()==ChessGame.BLACK){
			this.playerB_elapsed.add(time);
		}
		
		if (player.getColour()==ChessGame.WHITE){
			this.playerW_elapsed.add(time);
		}
	}
	
	/**
	 * Gets the total amount of time the player has spent moving pieces
	 * @param player The player to total up
	 * @return Total amount of time spent moving pieces
	 */
	public String getPlayerTime(Player player){
		long total=0;
		if (player.getColour()==ChessGame.BLACK){
			for (long t: this.playerB_elapsed){
				total+=t;
			}
		}else{
			for (long t: this.playerW_elapsed){
				total+=t;
			}
		}
		//System.out.println("Total time: "+total);
		return format(total); 
		//return ""+total;
		
	}

	/**
	 * This function converts an amount of time, given into milliseconds, into a string
	 * representation of the amount of time REMAINING (Total amount of time possible
	 * - the amount of time given), in an mm:ss format.
	 * @param time The amount of time taken
	 * @return String representation of time remaining
	 */
	private String format(long time){
		//subtracts time from 10 min and returns string format of result in mm:ss
		//long min =Math.round( (this.MAXTIME-time)/60000); //mins
		long secondsElapsed = Math.round(time/1000);
		long minsElapsed =Math.round(secondsElapsed/60); //mins elapsed
		secondsElapsed-=minsElapsed*60;
		//long seconds = Math.round( (this.MAXTIME-(min*60000)) %60000); 
		
		if (minsElapsed>=MAX_NUM_MINUTES){
			return "0:00";
		}
		
		long minsRemaining;
		long secondsRemaining;
		
		if (secondsElapsed==0){
			minsRemaining=10;
			secondsRemaining=0;
		}else{
			minsRemaining=9;
			secondsRemaining=60;
		}
		
		minsRemaining-=minsElapsed;
		secondsRemaining-=secondsElapsed;
		
		/*
		if (currentPlayer.getColour().equals(ChessGame.WHITE)){
			System.out.println("Mins Left: "+minsRemaining);
			System.out.println("Secs Left: "+secondsRemaining);
			System.out.println("Mins Elapsed: "+minsElapsed);
			System.out.println("Secs Elapsed: "+secondsElapsed);
		}
		*/
		
		//Construct the string
		String timeString = Long.toString(minsRemaining) + ":";
		if (secondsRemaining<10){
			timeString+="0";  //You want 5:09, not 5:9
		}
		timeString+=Long.toString(secondsRemaining);
		//return "Time Elapsed: "+minsElapsed+":"+secondsElapsed;
		if (timeString.length()>MAX_TIME_STRING_LENGTH){
			return "10:00";  
		}
		return timeString;
	}

	/**
	 * Starts a new turn for a player, and acts appropriately, adding the amount of time the previous
	 * player took into their time banks
	 * @param player The player whose turn it is now
	 */
	public void startNewTurn(Player player) {
		
		//Stuff to do if method is called properly with a player object
		if (player.getColour()==currentPlayer.getColour()){
			this.getRoundstart();
			//System.out.println();
		}
		if (player.getColour()!=currentPlayer.getColour()){
			//round over compute time
			this.getRoundend();
			this.updateTime(currentPlayer, this.findElapsed());
			//change turn over now that done computing last turn's time
			this.currentPlayer=player; //change player
			this.getRoundstart();			
		}
		
	}
	
	/**
	 * Switch to another player.  Used with commands to undo and redo time taking.
	 * @param player The player whose turn it will now be.
	 */
	public void switchPlayers(Player player){
		currentPlayer = player;
		this.getRoundstart();
	}
	
	
	/**
	 * Get the amount of time spent since the start of the turn, along with 
	 * the total amount of time spent prior to that.
	 * @return The amount of time (in milliseconds) since the start of the turn and with prior moves
	 */
	public String midturnClock(){
		//long time = this.starttime - System.currentTimeMillis();
		long time = System.currentTimeMillis() - this.starttime;
		//System.out.println("Time taken this turn: "+time);
		if (currentPlayer.getColour()==ChessGame.BLACK){
			for (long t: this.playerB_elapsed){
				time+=t;
			}
		}else{
			for (long t: this.playerW_elapsed){
				time+=t;
			}
		}
		return format(time);		
	}
	
	/**
	 * Removes the last added time from a players time bank and returns it.
	 * @param player The player to remove the time from
	 * @return The last time added to the players time banks
	 */
	private long poptime(Player player){
		
		if (player.getColour()==ChessGame.BLACK){
			return this.playerB_elapsed.remove(this.playerB_elapsed.size()-1);
		}
	
		if (player.getColour()==ChessGame.WHITE){
			return this.playerW_elapsed.remove(this.playerB_elapsed.size()-1);
		}
		
		return -1; //should not have minus time, this return is thrown as an illegal use of method
	}
	
	/**
	 * Undo a time event.
	 * @param player The player whose move is to be undone
	 * @return The amount of time that was removed from their clock
	 */
	public long undo(Player player){
		//a separate function is case undo requires other actions
		return poptime(player);
	}
	
	/**
	 * Gets the current status of the clock (Whether it is enabled or not)
	 * @return The state of the clock, whether it is enabled or not.
	 */
	public boolean isEnabled(){
		return this.clock_enable;
	}

	/**
	 * Get the amount of time spent since the start of the turn.
	 * @return Time spent (in milliseconds) since the start of the turn.
	 */
	public long getElapsedTime() {
		return System.currentTimeMillis() - this.starttime;
	}
	
	/**
	 * Gets the total amount of time that the black player has spent
	 * @return Time (in milliseconds) that the black player has spent
	 */
	public long getBlackTime(){
		long time = 0;
		for (long t: this.playerB_elapsed){
			time+=t;
		}
		return time;
	}
	
	/**
	 * Gets the total amount of time that the white player has spent
	 * @return Time (in milliseconds) that the white player has spent
	 */
	public long getWhiteTime(){
		long time = 0;
		for (long t: this.playerW_elapsed){
			time+=t;
		}
		return time;
	}

}
